{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# TensorFlow2.0教程-保持和读取模型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'2.0.0-alpha0'"
      ]
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from __future__ import absolute_import, division, print_function\n",
    "\n",
    "import os\n",
    "\n",
    "import tensorflow as tf\n",
    "from tensorflow import keras\n",
    "\n",
    "tf.__version__"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "导入数据"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "(train_images, train_labels), (test_images, test_labels) = tf.keras.datasets.mnist.load_data()\n",
    "\n",
    "train_labels = train_labels[:1000]\n",
    "test_labels = test_labels[:1000]\n",
    "\n",
    "train_images = train_images[:1000].reshape(-1, 28 * 28) / 255.0\n",
    "test_images = test_images[:1000].reshape(-1, 28 * 28) / 255.0"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1.定义一个模型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Model: \"sequential_2\"\n",
      "_________________________________________________________________\n",
      "Layer (type)                 Output Shape              Param #   \n",
      "=================================================================\n",
      "dense_4 (Dense)              (None, 128)               100480    \n",
      "_________________________________________________________________\n",
      "dropout_2 (Dropout)          (None, 128)               0         \n",
      "_________________________________________________________________\n",
      "dense_5 (Dense)              (None, 10)                1290      \n",
      "=================================================================\n",
      "Total params: 101,770\n",
      "Trainable params: 101,770\n",
      "Non-trainable params: 0\n",
      "_________________________________________________________________\n"
     ]
    }
   ],
   "source": [
    "def create_model():\n",
    "    model = keras.Sequential([\n",
    "        keras.layers.Dense(128, activation='relu', input_shape=(784,)),\n",
    "        keras.layers.Dropout(0.5),\n",
    "        keras.layers.Dense(10, activation='softmax')\n",
    "    ])\n",
    "\n",
    "    model.compile(optimizer='adam',\n",
    "                 loss=keras.losses.sparse_categorical_crossentropy,\n",
    "                 metrics=['accuracy'])\n",
    "    return model\n",
    "model = create_model()\n",
    "model.summary()\n",
    "    "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 2.checkpoint回调"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Train on 1000 samples, validate on 1000 samples\n",
      "Epoch 1/10\n",
      " 544/1000 [===============>..............] - ETA: 0s - loss: 2.0658 - accuracy: 0.2831 \n",
      "Epoch 00001: saving model to 106save/model.ckpt\n",
      "1000/1000 [==============================] - 1s 855us/sample - loss: 1.8036 - accuracy: 0.4190 - val_loss: 1.3101 - val_accuracy: 0.6700\n",
      "Epoch 2/10\n",
      " 800/1000 [=======================>......] - ETA: 0s - loss: 1.0327 - accuracy: 0.7125\n",
      "Epoch 00002: saving model to 106save/model.ckpt\n",
      "1000/1000 [==============================] - 0s 132us/sample - loss: 1.0101 - accuracy: 0.7190 - val_loss: 0.8742 - val_accuracy: 0.7650\n",
      "Epoch 3/10\n",
      " 768/1000 [======================>.......] - ETA: 0s - loss: 0.7168 - accuracy: 0.7865\n",
      "Epoch 00003: saving model to 106save/model.ckpt\n",
      "1000/1000 [==============================] - 0s 113us/sample - loss: 0.7214 - accuracy: 0.7900 - val_loss: 0.7212 - val_accuracy: 0.7950\n",
      "Epoch 4/10\n",
      " 992/1000 [============================>.] - ETA: 0s - loss: 0.5918 - accuracy: 0.8367\n",
      "Epoch 00004: saving model to 106save/model.ckpt\n",
      "1000/1000 [==============================] - 0s 90us/sample - loss: 0.5904 - accuracy: 0.8380 - val_loss: 0.6292 - val_accuracy: 0.8140\n",
      "Epoch 5/10\n",
      " 864/1000 [========================>.....] - ETA: 0s - loss: 0.4970 - accuracy: 0.8600\n",
      "Epoch 00005: saving model to 106save/model.ckpt\n",
      "1000/1000 [==============================] - 0s 105us/sample - loss: 0.4997 - accuracy: 0.8600 - val_loss: 0.5710 - val_accuracy: 0.8410\n",
      "Epoch 6/10\n",
      " 896/1000 [=========================>....] - ETA: 0s - loss: 0.4247 - accuracy: 0.8839\n",
      "Epoch 00006: saving model to 106save/model.ckpt\n",
      "1000/1000 [==============================] - 0s 97us/sample - loss: 0.4316 - accuracy: 0.8810 - val_loss: 0.5430 - val_accuracy: 0.8420\n",
      "Epoch 7/10\n",
      "  32/1000 [..............................] - ETA: 0s - loss: 0.2628 - accuracy: 0.9688\n",
      "Epoch 00007: saving model to 106save/model.ckpt\n",
      "1000/1000 [==============================] - 0s 81us/sample - loss: 0.3724 - accuracy: 0.8930 - val_loss: 0.5041 - val_accuracy: 0.8480\n",
      "Epoch 8/10\n",
      "  32/1000 [..............................] - ETA: 0s - loss: 0.2136 - accuracy: 0.9375\n",
      "Epoch 00008: saving model to 106save/model.ckpt\n",
      "1000/1000 [==============================] - 0s 75us/sample - loss: 0.3221 - accuracy: 0.9030 - val_loss: 0.4861 - val_accuracy: 0.8510\n",
      "Epoch 9/10\n",
      " 960/1000 [===========================>..] - ETA: 0s - loss: 0.3195 - accuracy: 0.9177\n",
      "Epoch 00009: saving model to 106save/model.ckpt\n",
      "1000/1000 [==============================] - 0s 108us/sample - loss: 0.3230 - accuracy: 0.9150 - val_loss: 0.4580 - val_accuracy: 0.8600\n",
      "Epoch 10/10\n",
      " 704/1000 [====================>.........] - ETA: 0s - loss: 0.2577 - accuracy: 0.9219\n",
      "Epoch 00010: saving model to 106save/model.ckpt\n",
      "1000/1000 [==============================] - 0s 128us/sample - loss: 0.2701 - accuracy: 0.9170 - val_loss: 0.4465 - val_accuracy: 0.8620\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<tensorflow.python.keras.callbacks.History at 0x7fbcd872fbe0>"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "check_path = '106save/model.ckpt'\n",
    "check_dir = os.path.dirname(check_path)\n",
    "\n",
    "cp_callback = tf.keras.callbacks.ModelCheckpoint(check_path, \n",
    "                                                 save_weights_only=True, verbose=1)\n",
    "model = create_model()\n",
    "model.fit(train_images, train_labels, epochs=10,\n",
    "         validation_data=(test_images, test_labels),\n",
    "         callbacks=[cp_callback])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "checkpoint  model.ckpt.data-00000-of-00001  model.ckpt.index\r\n"
     ]
    }
   ],
   "source": [
    "!ls {check_dir}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1000/1000 [==============================] - 0s 69us/sample - loss: 2.4036 - accuracy: 0.0890\n",
      "Untrained model, accuracy:  8.90%\n"
     ]
    }
   ],
   "source": [
    "model = create_model()\n",
    "\n",
    "loss, acc = model.evaluate(test_images, test_labels)\n",
    "print(\"Untrained model, accuracy: {:5.2f}%\".format(100*acc))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1000/1000 [==============================] - 0s 47us/sample - loss: 0.4465 - accuracy: 0.8620\n",
      "Untrained model, accuracy: 86.20%\n"
     ]
    }
   ],
   "source": [
    "model.load_weights(check_path)\n",
    "loss, acc = model.evaluate(test_images, test_labels)\n",
    "print(\"Untrained model, accuracy: {:5.2f}%\".format(100*acc))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3.设置checkpoint回调"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Train on 1000 samples, validate on 1000 samples\n",
      "Epoch 1/10\n",
      "1000/1000 [==============================] - 1s 1ms/sample - loss: 1.7242 - accuracy: 0.4490 - val_loss: 1.2205 - val_accuracy: 0.6890\n",
      "Epoch 2/10\n",
      "1000/1000 [==============================] - 0s 102us/sample - loss: 0.9133 - accuracy: 0.7450 - val_loss: 0.8194 - val_accuracy: 0.7800\n",
      "Epoch 3/10\n",
      "1000/1000 [==============================] - 0s 88us/sample - loss: 0.6489 - accuracy: 0.8360 - val_loss: 0.6748 - val_accuracy: 0.8050\n",
      "Epoch 4/10\n",
      "1000/1000 [==============================] - 0s 78us/sample - loss: 0.5492 - accuracy: 0.8360 - val_loss: 0.6144 - val_accuracy: 0.8150\n",
      "Epoch 5/10\n",
      "  32/1000 [..............................] - ETA: 0s - loss: 0.4468 - accuracy: 0.9062\n",
      "Epoch 00005: saving model to 106save02/cp-0005.ckpt\n",
      "1000/1000 [==============================] - 0s 130us/sample - loss: 0.4755 - accuracy: 0.8750 - val_loss: 0.5483 - val_accuracy: 0.8330\n",
      "Epoch 6/10\n",
      "1000/1000 [==============================] - 0s 94us/sample - loss: 0.4191 - accuracy: 0.8790 - val_loss: 0.5164 - val_accuracy: 0.8500\n",
      "Epoch 7/10\n",
      "1000/1000 [==============================] - 0s 107us/sample - loss: 0.3699 - accuracy: 0.8980 - val_loss: 0.4935 - val_accuracy: 0.8420\n",
      "Epoch 8/10\n",
      "1000/1000 [==============================] - 0s 87us/sample - loss: 0.3404 - accuracy: 0.9070 - val_loss: 0.4559 - val_accuracy: 0.8600\n",
      "Epoch 9/10\n",
      "1000/1000 [==============================] - 0s 85us/sample - loss: 0.3060 - accuracy: 0.9250 - val_loss: 0.4513 - val_accuracy: 0.8630\n",
      "Epoch 10/10\n",
      " 800/1000 [=======================>......] - ETA: 0s - loss: 0.3016 - accuracy: 0.9150\n",
      "Epoch 00010: saving model to 106save02/cp-0010.ckpt\n",
      "1000/1000 [==============================] - 0s 120us/sample - loss: 0.2845 - accuracy: 0.9220 - val_loss: 0.4402 - val_accuracy: 0.8580\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<tensorflow.python.keras.callbacks.History at 0x7fbc5c911b38>"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "check_path = '106save02/cp-{epoch:04d}.ckpt'\n",
    "check_dir = os.path.dirname(check_path)\n",
    "\n",
    "cp_callback = tf.keras.callbacks.ModelCheckpoint(check_path,save_weights_only=True, \n",
    "                                                 verbose=1, period=5)  # 每5\n",
    "model = create_model()\n",
    "model.fit(train_images, train_labels, epochs=10,\n",
    "         validation_data=(test_images, test_labels),\n",
    "         callbacks=[cp_callback])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "checkpoint\t\t\t  cp-0010.ckpt.data-00000-of-00001\r\n",
      "cp-0005.ckpt.data-00000-of-00001  cp-0010.ckpt.index\r\n",
      "cp-0005.ckpt.index\r\n"
     ]
    }
   ],
   "source": [
    "!ls {check_dir}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "载入最新版模型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "106save02/cp-0010.ckpt\n"
     ]
    }
   ],
   "source": [
    "latest = tf.train.latest_checkpoint(check_dir)\n",
    "print(latest)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1000/1000 [==============================] - 0s 78us/sample - loss: 0.4402 - accuracy: 0.8580\n",
      "restored model accuracy: 85.80%\n"
     ]
    }
   ],
   "source": [
    "model = create_model()\n",
    "model.load_weights(latest)\n",
    "loss, acc = model.evaluate(test_images, test_labels)\n",
    "print('restored model accuracy: {:5.2f}%'.format(acc*100))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 5.手动保持权重"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1000/1000 [==============================] - 0s 69us/sample - loss: 0.4402 - accuracy: 0.8580\n",
      "restored model accuracy: 85.80%\n"
     ]
    }
   ],
   "source": [
    "model.save_weights('106save03/manually_model.ckpt')\n",
    "model = create_model()\n",
    "model.load_weights('106save03/manually_model.ckpt')\n",
    "loss, acc = model.evaluate(test_images, test_labels)\n",
    "print('restored model accuracy: {:5.2f}%'.format(acc*100))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 6.保持整个模型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Train on 1000 samples, validate on 1000 samples\n",
      "Epoch 1/10\n",
      "1000/1000 [==============================] - 0s 240us/sample - loss: 1.7636 - accuracy: 0.4460 - val_loss: 1.2041 - val_accuracy: 0.7230\n",
      "Epoch 2/10\n",
      "1000/1000 [==============================] - 0s 82us/sample - loss: 0.9278 - accuracy: 0.7410 - val_loss: 0.7989 - val_accuracy: 0.7880\n",
      "Epoch 3/10\n",
      "1000/1000 [==============================] - 0s 97us/sample - loss: 0.6722 - accuracy: 0.7970 - val_loss: 0.6739 - val_accuracy: 0.8110\n",
      "Epoch 4/10\n",
      "1000/1000 [==============================] - 0s 110us/sample - loss: 0.5326 - accuracy: 0.8530 - val_loss: 0.6027 - val_accuracy: 0.8170\n",
      "Epoch 5/10\n",
      "1000/1000 [==============================] - 0s 88us/sample - loss: 0.4674 - accuracy: 0.8640 - val_loss: 0.5623 - val_accuracy: 0.8270\n",
      "Epoch 6/10\n",
      "1000/1000 [==============================] - 0s 91us/sample - loss: 0.3986 - accuracy: 0.8900 - val_loss: 0.5429 - val_accuracy: 0.8370\n",
      "Epoch 7/10\n",
      "1000/1000 [==============================] - 0s 87us/sample - loss: 0.3717 - accuracy: 0.8830 - val_loss: 0.5205 - val_accuracy: 0.8340\n",
      "Epoch 8/10\n",
      "1000/1000 [==============================] - 0s 100us/sample - loss: 0.3492 - accuracy: 0.8980 - val_loss: 0.4844 - val_accuracy: 0.8480\n",
      "Epoch 9/10\n",
      "1000/1000 [==============================] - 0s 90us/sample - loss: 0.3048 - accuracy: 0.9200 - val_loss: 0.4603 - val_accuracy: 0.8550\n",
      "Epoch 10/10\n",
      "1000/1000 [==============================] - 0s 90us/sample - loss: 0.2574 - accuracy: 0.9290 - val_loss: 0.4674 - val_accuracy: 0.8540\n"
     ]
    }
   ],
   "source": [
    "model = create_model()\n",
    "model.fit(train_images, train_labels, epochs=10,\n",
    "         validation_data=(test_images, test_labels),\n",
    "         )\n",
    "model.save('106save03.h5')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Model: \"sequential_11\"\n",
      "_________________________________________________________________\n",
      "Layer (type)                 Output Shape              Param #   \n",
      "=================================================================\n",
      "dense_22 (Dense)             (None, 128)               100480    \n",
      "_________________________________________________________________\n",
      "dropout_11 (Dropout)         (None, 128)               0         \n",
      "_________________________________________________________________\n",
      "dense_23 (Dense)             (None, 10)                1290      \n",
      "=================================================================\n",
      "Total params: 101,770\n",
      "Trainable params: 101,770\n",
      "Non-trainable params: 0\n",
      "_________________________________________________________________\n"
     ]
    }
   ],
   "source": [
    "new_model = keras.models.load_model('106save03.h5')\n",
    "new_model.summary()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1000/1000 [==============================] - 1s 810us/sample - loss: 0.4674 - accuracy: 0.8540\n",
      "restored model accuracy: 85.40%\n"
     ]
    }
   ],
   "source": [
    "loss, acc = model.evaluate(test_images, test_labels)\n",
    "print('restored model accuracy: {:5.2f}%'.format(acc*100))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 7.其他导出模型的方法"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "WARNING: Logging before flag parsing goes to stderr.\n",
      "W0326 20:00:41.243743 140450529666816 deprecation.py:323] From /home/czy/anaconda3/envs/tf2_0/lib/python3.6/site-packages/tensorflow/python/saved_model/signature_def_utils_impl.py:253: build_tensor_info (from tensorflow.python.saved_model.utils_impl) is deprecated and will be removed in a future version.\n",
      "Instructions for updating:\n",
      "This function will only be available through the v1 compatibility library as tf.compat.v1.saved_model.utils.build_tensor_info or tf.compat.v1.saved_model.build_tensor_info.\n",
      "W0326 20:00:41.244926 140450529666816 tf_logging.py:161] Export includes no default signature!\n",
      "W0326 20:00:41.639915 140450529666816 tf_logging.py:161] Export includes no default signature!\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'./saved_models/1553601639'"
      ]
     },
     "execution_count": 26,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import time\n",
    "saved_model_path = \"./saved_models/{}\".format(int(time.time()))\n",
    "\n",
    "tf.keras.experimental.export_saved_model(model, saved_model_path)\n",
    "saved_model_path"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Model: \"sequential_11\"\n",
      "_________________________________________________________________\n",
      "Layer (type)                 Output Shape              Param #   \n",
      "=================================================================\n",
      "dense_22 (Dense)             (None, 128)               100480    \n",
      "_________________________________________________________________\n",
      "dropout_11 (Dropout)         (None, 128)               0         \n",
      "_________________________________________________________________\n",
      "dense_23 (Dense)             (None, 10)                1290      \n",
      "=================================================================\n",
      "Total params: 101,770\n",
      "Trainable params: 101,770\n",
      "Non-trainable params: 0\n",
      "_________________________________________________________________\n"
     ]
    }
   ],
   "source": [
    "new_model = tf.keras.experimental.load_from_saved_model(saved_model_path)\n",
    "new_model.summary()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1000/1000 [==============================] - 0s 131us/sample - loss: 0.4674 - accuracy: 0.8540\n",
      "Restored model, accuracy: 85.40%\n"
     ]
    }
   ],
   "source": [
    "# 该方法必须先运行compile函数\n",
    "new_model.compile(optimizer=model.optimizer,  # keep the optimizer that was loaded\n",
    "              loss='sparse_categorical_crossentropy',\n",
    "              metrics=['accuracy'])\n",
    "\n",
    "# Evaluate the restored model.\n",
    "loss, acc = new_model.evaluate(test_images, test_labels)\n",
    "print(\"Restored model, accuracy: {:5.2f}%\".format(100*acc))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
